﻿using Abp.AspNetCore;
using Abp.Castle.Logging.Log4Net;
using Castle.Facilities.Logging;
using HCD.Web.Authorizer;
using HCD.Web.Hubs;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.IO;
using System.Reflection;
using System.Linq;
using Microsoft.OpenApi.Models;
using System.Globalization;
using Microsoft.AspNetCore.Localization;
using Swashbuckle.AspNetCore.SwaggerUI;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using WebLog;

namespace HCD.Web.Startup
{
    /// <summary>
    /// 启动配置
    /// </summary>
    public class Startup
    {    
        private readonly IConfiguration Configuration;

        //public IWeatherInfoAppService weatherInfoAppService { get; set; }
        /// <summary>
        /// Startup
        /// </summary>
        /// <param name="env"></param>
        public Startup(IWebHostEnvironment env)
        {
            var builder = new ConfigurationBuilder()
             .SetBasePath(env.ContentRootPath)
             .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
             .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
             .AddEnvironmentVariables();
            Configuration = builder.Build();
            JWTUtil.key = Configuration["Customization:JwtKey"];
        }

        /// <summary>
        /// ConfigureServices
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {            
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            services.AddSignalR();
            //services.AddSingleton<IServiceProvider, ServiceProvider>();
            services.AddMvc(options =>
            {
                // options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
                options.Filters.Add<IdempotenceFilter>();
                options.Filters.Add(typeof(AuthorFilter)); //身份过滤器
                options.Filters.Add(typeof(ExceptionResultFilter)); //异常过滤器
                var OpenWebLog = Configuration.GetValue<string>("OpenWebLog")?.ToLower() == "true";
                if (OpenWebLog) options.Filters.Add(typeof(WebLog.ResourceFilterAttribute));
            })
            .AddDataAnnotationsLocalization(options =>
            {
                options.DataAnnotationLocalizerProvider = (type, factory) =>
                    factory.Create(typeof(HCD.Resources.Localization.Resx.Lang));
            })
            .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
               //驼峰序列化方式：命名前几个字母连续大写，驼峰序列化方式 会把连续的大写全部变成小写，直到遇到小写字母和一些分隔字符
               //所以最优的方式首字母小写；如果非要首字母大写，第二个字母请小写
               options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
               options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss:fff";
               options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
               options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
            })
            .AddXmlSerializerFormatters()
            .AddRazorRuntimeCompilation();

            services.Configure<RequestLocalizationOptions>(options =>
            {
                var supportedCultures = new[] { new CultureInfo("zh"), new CultureInfo("en") };

                options.DefaultRequestCulture = new RequestCulture(culture: "zh", uiCulture: "zh");
                options.SupportedCultures = supportedCultures;
                options.SupportedUICultures = supportedCultures;
            });
            //允许跨域
            services.AddCors();
            //services.AddHostedService<PushService>();
#if DEBUG
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo
                {
                    Version = "v1",
                    Title = "HCD API"
                });
                options.DocInclusionPredicate((docName, description) => true);
                options.OperationFilter<ApiHeaderToken>();
                options.DocumentFilter<ApplyDocumentVendorExtensions>();
                var currentAssembly = Assembly.GetExecutingAssembly();
                var xmlDocs = currentAssembly.GetReferencedAssemblies()
                .Union(new AssemblyName[] { currentAssembly.GetName() })
                .Select(a => Path.Combine(Path.GetDirectoryName(currentAssembly.Location), $"{a.Name}.xml"))
                .Where(f => File.Exists(f)).ToArray();
                Array.ForEach(xmlDocs, (d) =>
                {
                    options.IncludeXmlComments(d);
                });
            });
#endif
            services.AddSingleton(Configuration);

            services.Configure<IISOptions>(options =>
            {
                options.ForwardClientCertificate = false;
            });

            //services.AddHangfire(r => r.UseSqlServerStorage(Configuration.GetConnectionString("Default")));
            //weblog日志
            WebLogResourceInit();
            //Configure Abp and Dependency Injection
            return services.AddAbp<EnterpriseWebModule>(options =>
            {
                //Configure Log4Net logging
                options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                    f => f.UseAbpLog4Net().WithConfig("log4net.config")
                );
            });
        }

        /// <summary>
        /// Configure
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="loggerFactory"></param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            app.UseAbp();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Error/Index");
            }
           
            app.UseStaticFiles(new StaticFileOptions()
            {
                ContentTypeProvider = new FileExtensionContentTypeProvider()
                {
                    Mappings =
                    {
                        [".exe"] = "application/octect-stream" ,
                        [".manifest"] = "application/x-ms-manifest",
                        [".application"] = "application/x-ms-application",
                        [ ".apk"]= "application/vnd.android.package-archive"
                    }
                }
            });
            app.UseCors(c => c.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
#if DEBUG
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "HCD API V1");
                c.DocExpansion(DocExpansion.None);
                c.DefaultModelsExpandDepth(-1);
            });
#endif
            app.UseWebSockets();
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub<SystemHub>("/systemHub");
                endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
                //endpoints.MapRazorPages();
            });
            //weblog日志
            app.UseWebLog();
            //app.UseHangfireDashboard();//启动hangfire面板
            //app.UseHangfireServer(//启动Hangfire服务
            //    new BackgroundJobServerOptions
            //    {
            //        Queues = new[] { "test", "default" },//队列名称，只能为小写
            //        WorkerCount = Environment.ProcessorCount * 5, //并发任务数
            //        ServerName = "hangfire1",//服务器名称
            //    });
        }
        #region weblog 资源初始化
        #region DefineLoggerFactory     
        public static readonly ILoggerFactory EFLoggerFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });
        #endregion DefineLoggerFactory
        private class myTypeFactory : WebLog.ITypeFactory//类型工厂 用于处理一些weblog库没有的类型的构建
        {
            public void SendMsg(string msg, string msgTitle = "内部消息推送")
            {
                //MSGHelper.notSendMsgs.Enqueue((msg, msgTitle));
                //IocResolver.SendMsg(null, msg, msgTitle);//解决不了依赖注入 这一步无法完成
            }

            public object CreateBaseBizResult(string Message, bool Success = false, int? errorCode = null, object errorData = null, object data = null)
            {
                var result = new Partner.Utility.BizResult<object>();
                result.Message = Message;
                result.Success = Success;
                if (errorCode.HasValue)
                    result.ErrorCode = (Partner.Utility.ErrorCodeEnum)errorCode;
                result.ErrorData = errorData;
                result.Data = data;
                return result;
            }

            public Exception CreateBizException(string errMsg, int? errorCode = null, object errorData = null)
             => new Partner.Utility.BizException(errMsg, errorCode.HasValue ? (Partner.Utility.ErrorCodeEnum?)errorCode.Value : null, errorData);

            public Type GetBaseBizResultType() => typeof(Partner.Utility.BaseBizResult);
        }

        private void WebLogResourceInit()
        {
            EFLoggerFactory.AddProvider(new WebLog.WebLog_LoggerProvider(DbLoggerCategory.Database.Command.Name));            
            WebLog.Common.Binds.BindTypeFactory(new myTypeFactory());
        }

        #endregion weblog 资源初始化
    }
}